package syferserver;

import java.net.Socket;
import java.io.*;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;

public class CommunicationHandler extends Thread {

    public UDPStream udp = null;
    private Socket socket = null;
    private PrintWriter schrijver;
    private BufferedReader lezer;
    private String channel;
    private String nickname;
    private Channel c;
    private int poort;

    public CommunicationHandler(Socket socket, Channel c) {
        this.c = c;
        try {
            this.socket = socket;
            this.lezer = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            this.schrijver = new PrintWriter(socket.getOutputStream(), true);
            this.nickname = "Guest0";
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    /**
     * Geeft mensen die joinen een gasten naam
     * @param nummer om bij de Guest naam te zetten automatisch increment als naam in gebruik is
     * @return naam
     */
    private String assignNickname(int nummer) {
        String naam;
        if (nummer > 1) {
            naam = "Guest" + nummer;
        } else {
            naam = "Guest";
        }

        if (isNicknameInUse(naam)) {
            return assignNickname(nummer + 1);
        } else {
            return naam;
        }
    }

    /**
     * checkt of er al iemand op dit channel deze naam gebruikt
     * @param name
     * @return
     */
    private boolean isNicknameInUse(String name) {
        for (int i = 0; i < this.c.communications.size(); i++) {
            if (this.channel.equals(c.communications.get(i).getChannel()) && c.communications.get(i).nickname.equals(name)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public void run() {

        handleData();
    }

    public void sendData(String data) {
        //System.out.println("To client: " + data);
        schrijver.println(data);
    }

    //stuurt naar iedereen op zelfde kanaal nieuwe user joined
    //newuser:naam
    private void sendNewUserJoinedChannel(String nickname) {
        for (CommunicationHandler u : c.communications) {
            if (u.getChannel().equals(this.getChannel())) {
                u.sendData("newuser:" + nickname);
            }
        }
    }

    //stuurt naar iedereen dat deze user is weg gegaan
    private void sendUserLeftChannel() {
        for (CommunicationHandler u : c.communications) {
            if (u.getChannel().equals(this.getChannel())) {
                u.sendData("userleft:" + this.getNickname());
            }
        }
    }

    //stuurt naar iedereen user changed nickname
    //nickname:nieuwe naam:oude naam
    private void nicknameChange(String nickname) {
        if (!isNicknameInUse(nickname)) {
            for (CommunicationHandler u : c.communications) {
                if (u.getChannel().equals(this.getChannel())) {
                    u.sendData("nickname:" + nickname + ":" + this.nickname);
                }
            }
            this.nickname = nickname;
        } else {
            this.sendData("error:" + nickname + "is already in ");
        }

    }

    private void sendOnlineUsers() {
        String users = "";
        for (CommunicationHandler u : c.communications) {
            if (u.getChannel().equals(this.getChannel()) && !this.nickname.equals(u.getNickname())) {
                users += ":" + u.nickname;
            }
        }
        if (!users.equals("")) {
            this.sendData("users" + users);
        }
    }

    private void startUDP(String hostname, int in, int uit) {
        System.out.println("Server: starting udp");
        udp = new UDPStream(hostname, in, uit);
        try {
            Thread.sleep(20);
        } catch (InterruptedException ex) {
        }
        udp.start();
    }

    private void handleData() {
        String msgReceived;
        try {
            while ((msgReceived = lezer.readLine()) != null) {
                String[] tmp = msgReceived.split(":");

                //udp poort voor heen te schrijven
                if (tmp[0].equals("port")) {
                    System.out.println("poort ontvangen:" + tmp[1]);
                    this.poort = Integer.parseInt(tmp[1]);
                    startUDP(socket.getInetAddress().getHostAddress(), c.getPort(), this.poort);

                    synchronized (c.communications) {
                        c.communications.addElement(this);
                    }
                }

                //new user joining channel
                if (tmp[0].equals("channel")) {
                    this.channel = tmp[1];
                    this.nickname = assignNickname(1);
                    sendOnlineUsers();
                    sendNewUserJoinedChannel(this.getNickname());
                }

                //user sets nickname
                if (tmp[0].equals("nickname")) {
                    nicknameChange(tmp[1].trim());
                }
            }
        } catch (IOException ex) { //disconnect from server
            try {
                System.out.println(socket.getRemoteSocketAddress() + " has left the server");
                synchronized (c.communications) {
                  udp.w.stop();
                  udp.r.stop();
                    udp=null;
                    c.communications.removeElement(this);
                }
                lezer.close();
                schrijver.close();
                socket.close();
                sendUserLeftChannel();
                this.stop();
            } catch (IOException ex1) {
                ex1.printStackTrace();
            }
            //ex.printStackTrace();
        }
    }

    public Socket getSocket() {
        return this.socket;
    }

    public String getChannel() {
        return channel;
    }

    public String getNickname() {
        return nickname;
    }
}
